//============================================================================
// Name        : 3DCTS.cpp
// Author      : Hu XU
// Created on  : Oct 26, 2011
// Copyright   : Copyright Reserved
// Description : 3D clock tree synthesis
//============================================================================

#include <iostream>
#include <fstream>
#include "Layout.h"
#include "Conf.h"
#include <time.h>

using namespace std;

// functions
void help_info() {
	cout << "  Help" << endl;
	cout << "  -s setup_file    # Includes process and voltage info." << endl;
	cout << "  -i input_file    # Includes 3D sink location." << endl;
	cout
		<< "  -d [output_directory]    # Stored in current directory by default."
		<< endl;
	cout
		<< "  -o [output_file]   # Output file, in the same name as the input_file by default"
		<< endl << endl;
}

int main(int argc, const char* argv[]) {

	string setupname="", ifname="";	// setup file and circuit file
	string ofname="", logname="";
	string prompt;
	unsigned int pos1, pos2;
	time_t tstart, tend, date;
	double cputime = 0;
	string OUTDIR = ".";
	string prog_name = argv[0];
	
	pos1 = prog_name.rfind("/"); // linux
	if(pos1==string::npos)
		pos1 = prog_name.rfind("\\"); // windows
	prog_name = prog_name.substr(pos1 + 1, prog_name.size());

	/* determine file name */
	cout << endl << " *** " << prog_name << " ******************* " << endl;
	cout << " ------------------------------------------- "<< endl;
	// read in paramters
	// at least setup and input files are required
	for (int i = 1; i <= argc - 1; i++) {
		if (argv[i][0] == '-') {
			// an option
			switch (argv[i][1]) {
			case 's':
				setupname = argv[++i];
				break;
			case 'i':
				ifname = argv[++i];
				break;
			case 'o':
				ofname = argv[++i];
				break;
			case 'd':
				OUTDIR = argv[++i];
				break;
			}
		} else
			i++; // skip the option
	}

	try {
		/* read in the setup file */
		ifstream setupstream(setupname.c_str(), ios::in);
		if (!setupstream) {
			string err_info = " No setup file \"" + ifname + "\"!";
			help_info();
			throw(err_info);
		} else{
			cout << " * Read setup file \"" << setupname << "\"." << endl;
		}

		/* read in the circuit file */
		ifstream filein(ifname.c_str(), ios::in);

		if (!filein) {
			string err_info = " No circuit file \"" + ifname + "\"!";
			help_info();
			throw(err_info);
		} else {
			cout << " * Read circuit file \"" << ifname << "\"." << endl;
		}

		/* define output and log files */
		if(ofname == ""){
			// output is not specified
			ofname = ifname;
			pos1 = ofname.find(".txt");
			pos2 = ofname.rfind("/");
			if(pos2==string::npos)
				pos2 = ofname.rfind("\\");

			stringstream sstemp;
			sstemp << "_CTS";

			if(pos1!=string::npos)
				ofname.insert(pos1, sstemp.str());
			else{
				string err_info = "Output file \"" + ofname + "\" is not a .txt file!";
				help_info();
				throw(err_info);
			}

			if (pos2!=string::npos){
				// "/" is found
				ofname.replace(0, pos2, OUTDIR);
			} else {
				// no "/" or "\" in ofname
				ofname.insert(0, OUTDIR);
				if(ofname.find("\\")==string::npos && ofname.find("/")==string::npos){
					string err_info = ofname + " is not a valid output file name!";
					throw(err_info);
				}					
			}
		}

		// for log
		logname = ofname;
		pos1 = logname.find(".txt");
		if(pos1 != string::npos)
			logname.replace(pos1, sizeof(".txt"), ".log");
		else{
			string err_info = "Output file \"" + ofname + "\" is not a .txt file!";
			help_info();
			throw(err_info);
		}

		// check output file
		fstream fileout(ofname.c_str());
		if (!fileout){
			prompt = " * Writing to \"" + ofname + "\".\n";
			cout << prompt;
		}
		else{
			prompt = " * Overwriting \"" + ofname + "\"? (y/n): ";
			cout << prompt;
			char is_overwrite = 'n';
			cin >> is_overwrite;
			if(is_overwrite == 'n')
				throw(" User terminated.");
		}
		fileout.close();

		/* CTS */
		cout << " * Synthesizing \"" << ifname << "\""<< endl;
		tstart = clock();
		Layout<int> circuit(setupstream, filein);

		// output
		tend = clock();
		date = time(NULL);
		cputime = (tend - tstart) / double(CLOCKS_PER_SEC);

		fileout.open(ofname.c_str(), ios::out);
		fileout << "# Generated by 3DCTS." << endl;
		fileout << "# Date: " << ctime(&date);
		fileout << "# CPU time: " << cputime << " s." << endl << endl;
		fileout << circuit;

		fileout.close();
		filein.close();
		cout << " Successfully executed!" <<endl;
	} catch (string & errinfo) {
		cerr << errinfo << endl;
	} catch (char const *a){
		cerr << a << endl;
	}

	return 0;
}
